#include "ReleaseCP.hpp"

using namespace BFT::messages;

ReleaseCP::ReleaseCP(boost::shared_ptr<char> _token, int _token_size, uint32_t _seqNo, uint32_t _sender)
	: MacArrayMessage::MacArrayMessage(RELEASE_CP, computeSize(_token_size), _sender, BFT::Parameters::getExecutionCount())
{
	seqNo = _seqNo;
	token_size = _token_size;
	token = _token;
	
	int bytes_size;
	boost::shared_ptr<char> bytes = getBytes(bytes_size);
	
	unsigned int offset = getOffset();
	
	//write  the sequence number
	*(uint32_t*)(bytes.get()+offset) = htonl((uint32_t)seqNo);
	offset += SEQUENCE_NUMBER_SIZE;
	
	//write the token size
	*(uint32_t*)(bytes.get()+offset) = htonl((uint32_t)token_size);
	offset += TOKEN_SIZE_SIZE;
	
	//write the token
	memcpy( (void*)(bytes.get()+offset) , (const void*)(token.get()) ,  token_size);
	offset += token_size;
}

ReleaseCP::ReleaseCP(boost::shared_ptr<char> _bytes, int _bytes_size)
	: MacArrayMessage::MacArrayMessage(_bytes, _bytes_size)
{
	if (getTag() != RELEASE_CP)
	{
		fprintf(stderr, "trying to construct a ReleaseCP from invalid bytes. expected tag:%d, actual tag:%d\n",RELEASE_CP, getTag());
		exit(103);
	}
	
	unsigned int offset = getOffset();
	
	//read the sequence number
	seqNo = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset =+ SEQUENCE_NUMBER_SIZE;
	
	//read the soze of the token
	token_size = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset += TOKEN_SIZE_SIZE;
	
	token.reset( (char*)malloc(token_size), free);

	//read the token
	memcpy( (void*)(token.get()) , (const void *)(_bytes.get()+offset) , token_size);
	offset += token_size;
	
	if (offset != _bytes_size - getAuthenticationSize())
	{
		fprintf(stderr, "trying to build a ReleaseCP from invalid bytes\n");
		exit(104);
	} 
}

bool ReleaseCP::equals(boost::shared_ptr<ReleaseCP> _other_rcp)
{
	bool equal = MacArrayMessage::equals(_other_rcp) &&
		     seqNo == _other_rcp.get()->getSequenceNumber() &&
		     token_size == _other_rcp.get()->getTokenSize() &&
		     getSendingReplica() == _other_rcp.get()->getSendingReplica();
	boost::shared_ptr<char> other_token = _other_rcp.get()->getToken();
	for(int i=0; i< token_size && equal; i++)
	{
		equal = token.get()[i] == other_token.get()[i];
	}
	
	return equal;
} 

bool ReleaseCP::matches(boost::shared_ptr<VerifiedMessageBase> _other_vmb)
{
	//TODO find a better way to safely downcast
	//boost::shared_ptr<ReleaseCP> other_rcp = boost::static_pointer_cast<ReleaseCP> (_other_vmb);
	
	int rcp_size;
	boost::shared_ptr<char> rcp_bytes = _other_vmb.get()->getBytes(rcp_size);
	boost::shared_ptr<ReleaseCP> other_rcp (new ReleaseCP(rcp_bytes,rcp_size));
	
	bool match = seqNo == other_rcp.get()->getSequenceNumber()&&
		     token_size == other_rcp.get()->getTokenSize();
	if(match)
	{
		boost::shared_ptr<char> other_token = other_rcp.get()->getToken();
		for(int i=0; i< token_size && match; i++)
			match = token.get()[i] == other_token.get()[i];
	}
	
	return match;	
}

uint32_t ReleaseCP::computeSize(int _token_size)
{
	return SEQUENCE_NUMBER_SIZE + TOKEN_SIZE_SIZE + _token_size;
}

void ReleaseCP::printInfo()
{
	fprintf(stdout,"ReleaseCP information...\n");
	fprintf(stdout,"seqNo: %d\ntoken size: %d\ntoken omitted... ",seqNo, token_size);
//	for (int i=0; i< token_size; i++)
//		fprintf(stdout,"|%02X",(unsigned char)token.get()[i]);
//	fprintf(stdout,"\n");
}
